﻿#include "MaterialVectorOperationNodeViewModel.h"

#include "MaterialVectorOperationNodeModel.h"
#include "MaterialGraph/Pin/MaterialGraphPinViewModel.h"
#include "MaterialGraph/Pin/MaterialGraphPinModel.h"
#include "MaterialGraph/MaterialGraphViewModel.h"

void RMaterialVectorOperationNodeViewModel::BindModel(TSharedObjectPtr<RMaterialGraphNodeModel> InModel, TSharedObjectPtr<RMaterialGraphViewModel> InGraph)
{
    Super::BindModel(InModel, InGraph);
    OperationModel = InModel;

    //分配行号
    OperationModel->OnOperationTypeChanged
    .Bind([this]()
    {
        ReassignLineNumberAndNodeHeight();
    });
    ReassignLineNumberAndNodeHeight();
    for(int64_t i=0; i<3; ++i)
    {
        //当向量输入引脚连接状态改变时，重新分配行号
        //因为没有连接的向量输入占用4行，而连接了的向量输入占用1行
        InputViewModels[i]->OnLinkChanged.Bind([this]()
        {
            ReassignLineNumberAndNodeHeight();
        });
    }
}

int64_t RMaterialVectorOperationNodeViewModel::GetLineNum() const
{
    return TotalLineNum;
}

CString RMaterialVectorOperationNodeViewModel::GetInputPinName(int64_t Index) const
{

    switch(OperationModel->GetOperationType())
    {
        case EMaterialVectorOperationType::Divide:
        {
            switch (Index)
            {
                case 0:
                    return U"被除数";
                case 1:
                    return U"除数";
            }
            break;
        }

        case EMaterialVectorOperationType::AddAfterMultiply:
        {
            switch (Index)
            {
                case 0:
                    return U"向量A";
                case 1:
                    return U"向量B";
                case 2:
                    return U"增加的向量";
            }
            break;
        }

        case EMaterialVectorOperationType::Reflect:
        {
            switch (Index)
            {
                case 0:
                    return U"入射向量";
                case 1:
                    return U"法线";
            }
            break;
        }

        case EMaterialVectorOperationType::Refract:
        {
            switch (Index)
            {
                case 0:
                    return U"入射向量";
                case 1:
                    return U"法线";
                case 3:
                    return U"折射率";
            }
            break;
        }

        case EMaterialVectorOperationType::FaceForward:
        {
            switch (Index)
            {
                case 0:
                    return U"任意向量A";
                case 1:
                    return U"视线B";
                case 2:
                    return U"法线C";
            }
            break;
        }

        case EMaterialVectorOperationType::Scale:
        {
            switch (Index)
            {
                case 0:
                    return U"向量";
                case 3:
                    return U"缩放值";
            }
            break;
        }

        case EMaterialVectorOperationType::Mod:
        {
            switch (Index)
            {
                case 0:
                    return U"被除数";
                case 1:
                    return U"除数";
            }
            break;
        }

        case EMaterialVectorOperationType::Loop:
        {
            switch (Index)
            {
                case 0:
                    return U"向量";
                case 1:
                    return U"最小值";
                case 2:
                    return U"最大值";
            }
            break;
        }

        case EMaterialVectorOperationType::Snap:
        {
            switch (Index)
            {
                case 0:
                    return U"向量";
                case 1:
                    return U"网格大小";
            }
            break;
        }

    }



    switch(Index)
    {
        case 0:
            return U"向量A";
        case 1:
            return U"向量B";
        case 2:
            return U"向量C";
        case 3:
            return U"数值";
        default:
            assert(false);
            return U"";
    }
}

CString RMaterialVectorOperationNodeViewModel::GetOperationName() const
{
    return WHE::ToString(OperationModel->GetOperationType());
}

EMaterialVectorOperationType RMaterialVectorOperationNodeViewModel::GetOperationType() const
{
    return OperationModel->GetOperationType();
}

void RMaterialVectorOperationNodeViewModel::SetOperationType(EMaterialVectorOperationType InOperationType)
{
    auto CurrentOperationType=OperationModel->GetOperationType();
    auto NewOperationType=InOperationType;

    auto Operation= NewObject<RMaterialFunctionOperation>();
    auto Model=OperationModel;
    Operation->UndoFunction.Bind([Model,CurrentOperationType](TSharedObjectPtr<RMaterialGraphModel> InGraph)
    {
        Model->SetOperationType(CurrentOperationType);
    });
    Operation->RedoFunction.Bind([Model,NewOperationType](TSharedObjectPtr<RMaterialGraphModel> InGraph)
    {
        Model->SetOperationType(NewOperationType);
    });

    GraphViewModel->RedoOperation(Operation);
    GraphViewModel->AddOperation(Operation); 
}

bool RMaterialVectorOperationNodeViewModel::IsOutputFloat() const
{
    switch(GetOperationType())
    {
        case EMaterialVectorOperationType::Length:
        case EMaterialVectorOperationType::DotProduct:
        case EMaterialVectorOperationType::Distance:
        {
            return true;
        }
        default:
        {
            return false;
        }
    }
}

void RMaterialVectorOperationNodeViewModel::ReassignLineNumberAndNodeHeight()
{
    OutputViewModels[0]->SetLineIndex(1);
    OutputViewModels[1]->SetLineIndex(1);
    
    int32_t CurrentLine=3;
    switch(GetOperationType())
    {
        case EMaterialVectorOperationType::Absolute:
        case EMaterialVectorOperationType::Floor:
        case EMaterialVectorOperationType::Ceil:
        case EMaterialVectorOperationType::Fraction:
        case EMaterialVectorOperationType::Round:
        case EMaterialVectorOperationType::Normalize:
        case EMaterialVectorOperationType::Sin:
        case EMaterialVectorOperationType::Cos:
        case EMaterialVectorOperationType::Tan:
        {
            //需要一个向量输入和一个向量输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+=InputViewModels[0]->HasValidLink()? 1:4;
            break;
        }

        case EMaterialVectorOperationType::Add:
        case EMaterialVectorOperationType::Subtract:
        case EMaterialVectorOperationType::Multiply:
        case EMaterialVectorOperationType::Divide:
        case EMaterialVectorOperationType::CrossProduct:
        case EMaterialVectorOperationType::Project:
        case EMaterialVectorOperationType::Reflect:
        case EMaterialVectorOperationType::Minimum:
        case EMaterialVectorOperationType::Maximum:
        case EMaterialVectorOperationType::Mod:
        case EMaterialVectorOperationType::Snap:
        {
            //需要两个向量输入和一个向量输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[0]->HasValidLink()? 1:4;
            InputViewModels[1]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[1]->HasValidLink()? 1:4;
            break;
        }

        case EMaterialVectorOperationType::AddAfterMultiply:
        case EMaterialVectorOperationType::FaceForward:
        case EMaterialVectorOperationType::Loop:
        {
            //需要三个向量输入和一个向量输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[0]->HasValidLink()? 1:4;
            InputViewModels[1]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[1]->HasValidLink()? 1:4;
            InputViewModels[2]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[2]->HasValidLink()? 1:4;
            break;
        }

        case EMaterialVectorOperationType::Length:
        {
            //需要一个向量输入和一个浮点输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[0]->HasValidLink()? 1:4;
            break;
        }

        case EMaterialVectorOperationType::DotProduct:
        case EMaterialVectorOperationType::Distance:
        {
            //需要两个向量输入和一个浮点输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[0]->HasValidLink()? 1:4;
            InputViewModels[1]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[1]->HasValidLink()? 1:4;
            break;
        }

        case EMaterialVectorOperationType::Scale:
        {
            //需要一个向量输入和一个浮点输入和一个向量输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[0]->HasValidLink()? 1:4;
            InputViewModels[3]->SetLineIndex(CurrentLine);
            CurrentLine+=1;
            break;
        }

        case EMaterialVectorOperationType::Refract:
        {
            //需要两个向量输入和一个浮点输入和一个向量输出
            InputViewModels[0]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[0]->HasValidLink()? 1:4;
            InputViewModels[1]->SetLineIndex(CurrentLine);
            CurrentLine+= InputViewModels[1]->HasValidLink()? 1:4;
            InputViewModels[3]->SetLineIndex(CurrentLine);
            CurrentLine+=1;
            break;
        }

        default:
        {
            assert(false);
        }
    }

    TotalLineNum = CurrentLine;
    //让视图层重新绘制
    OnNodeLineChanged.ExecuteIfBound();
}
